﻿// -----------------------------------------------------------------------------------------------
//  <copyright file="MainWindow.xaml.cs" company="http://buginbox.wordpress.com/">
//    Copyright (c) GNU General Public License version 2 (GPLv2)
//  </copyright>
// -----------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;

using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

using TestPlanMigration.Tree;

using MessageBox = System.Windows.MessageBox;
using TreeView = System.Windows.Controls.TreeView;

namespace TestPlanMigration
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        #region Properties

        /// <summary>
        /// The Tfs Config for source.
        /// </summary>
        private TfsConfig _tfsConfigSource;

        /// <summary>
        /// The test projects for source.
        /// </summary>
        private readonly List<TfsProjectTest> _sourceTestProjects = new List<TfsProjectTest>();

        /// <summary>
        /// Gets Source Project.
        /// </summary>
        private TfsProjectTest _sourceProject
        {
            get
            {
                return _sourceTestProjects.Count == 1 ? _sourceTestProjects[0] : null;
            }
        }

        /// <summary>
        /// The Tfs Config for destination.
        /// </summary>
        private TfsConfig _tfsConfigDestination;

        /// <summary>
        /// The test projects for destination.
        /// </summary>
        private readonly List<TfsProjectTest> _destinationTestProjects = new List<TfsProjectTest>();

        /// <summary>
        /// Gets Destination Project.
        /// </summary>
        private TfsProjectTest _destinationProject
        {
            get
            {
                return _destinationTestProjects.Count == 1 ? _destinationTestProjects[0] : null;
            }
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="MainWindow"/> class.
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();
        }

        #endregion

        #region UI

        /// <summary>
        /// Buttons the source connect click.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void ButtonSourceConnectClick(object sender, RoutedEventArgs e)
        {
            var tpp = new TeamProjectPicker(TeamProjectPickerMode.SingleProject, false);

            if (tpp.ShowDialog() != System.Windows.Forms.DialogResult.OK)
            {
                return;
            }

            using (new WaitCursor())
            {
                if (tpp.SelectedTeamProjectCollection != null)
                {
                    if (tpp.SelectedProjects.Length != 1)
                    {
                        return;
                    }

                    var projectInfo = tpp.SelectedProjects[0];

                    _tfsConfigSource = TfsConfig.NewConfiguration(tpp.SelectedTeamProjectCollection);

                    foreach (Project project in _tfsConfigSource.WorkItemStore.Projects)
                    {
                        if (project.Name == projectInfo.Name)
                        {
                            RefreshSource(project);

                            TfsProjectTest projectTest = TfsProjectTest.NewTestProject(_tfsConfigSource, project);
                            _sourceTestProjects.Add(projectTest);

                            TfsTestTreeViewBuilder.BuidTreeViewFromTestPlans(projectTest, TreeMain);

                            break;
                        }
                    }

                    RefreshUI();
                }
            }
        }

        /// <summary>
        /// Buttons the destination connect click.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void ButtonDestinationConnectClick(object sender, RoutedEventArgs e)
        {
            var tpp = new TeamProjectPicker(TeamProjectPickerMode.SingleProject, false);

            if (tpp.ShowDialog() != System.Windows.Forms.DialogResult.OK)
            {
                return;
            }

            using (new WaitCursor())
            {
                if (tpp.SelectedTeamProjectCollection != null)
                {
                    if (tpp.SelectedProjects.Length != 1)
                    {
                        return;
                    }

                    var projectInfo = tpp.SelectedProjects[0];

                    _tfsConfigDestination = TfsConfig.NewConfiguration(tpp.SelectedTeamProjectCollection);

                    foreach (Project project in _tfsConfigDestination.WorkItemStore.Projects)
                    {
                        if (project.Name == projectInfo.Name)
                        {
                            RefreshDestination(project);

                            TfsProjectTest projectTest = TfsProjectTest.NewTestProject(_tfsConfigDestination, project);
                            _destinationTestProjects.Add(projectTest);

                            break;
                        }
                    }

                    RefreshUI();
                }
            }
        }

        /// <summary>
        /// Refreshes the source.
        /// </summary>
        /// <param name="project">The project.</param>
        private void RefreshSource(Project project)
        {
            if (project == null)
            {
                LabelSource.Content = "...";
            }
            else
            {
                LabelSource.Content = _tfsConfigSource.ProjectCollection.Name + @"\" + project.Name;
            }
        }

        /// <summary>
        /// Refreshes the destination.
        /// </summary>
        /// <param name="project">The project.</param>
        private void RefreshDestination(Project project)
        {
            if (project == null)
            {
                LabelDestination.Content = "...";
            }
            else
            {
                LabelDestination.Content = _tfsConfigDestination.ProjectCollection.Name + @"\" + project.Name;
            }
        }

        /// <summary>
        /// Refreshes the UI.
        /// </summary>
        private void RefreshUI()
        {
            if (_sourceProject == null)
            {
                ButtonDestinationConnect.IsEnabled = false;
            }
            else
            {
                ButtonDestinationConnect.IsEnabled = true;
            }

            if (_sourceProject == null || _destinationProject == null)
            {
                ButtonMigrate.IsEnabled = false;
            }
            else
            {
                ButtonMigrate.IsEnabled = true;
            }
        }

        /// <summary>
        /// Clears the UI.
        /// </summary>
        private void ClearUI()
        {
            _tfsConfigSource = null;
            _sourceTestProjects.Clear();
            RefreshSource(null);

            _tfsConfigDestination = null;
            _destinationTestProjects.Clear();
            RefreshDestination(null);

            TreeMain.Items.Clear();

            RefreshUI();
        }

        #region TreeView Contextual Menu Management

        /// <summary>
        /// Called when [preview mouse right button down].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
        private void TreeMainPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            TreeViewItem treeViewItem = VisualUpwardSearch(e.OriginalSource as DependencyObject);

            if (treeViewItem != null)
            {
                treeViewItem.Focus();
                e.Handled = true;
            }
        }

        /// <summary>
        /// Visuals the upward search.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <returns></returns>
        private static TreeViewItem VisualUpwardSearch(DependencyObject source)
        {
            while (source != null && !(source is TreeViewItem))
            {
                source = VisualTreeHelper.GetParent(source);
            }

            return source as TreeViewItem;
        }

        /// <summary>
        /// Trees the main selected item changed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="object"/> instance containing the event data.</param>
        private void TreeMainSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            var treeView = (TreeView)sender;
            var selectedItem = treeView.SelectedItem as TreeViewItem;

            if (selectedItem == null)
            {
                return;
            }

            var item = (TfsTestItem)selectedItem.Tag;

            switch (item.Type)
            {
                case TfsTestItemType.TestPlan:
                    treeView.ContextMenu = treeView.Resources["PlanContextMenu"] as System.Windows.Controls.ContextMenu;
                    break;

                case TfsTestItemType.TestSuite:
                    treeView.ContextMenu = treeView.Resources["SuiteContextMenu"] as System.Windows.Controls.ContextMenu;
                    break;

                case TfsTestItemType.TestCase:
                    treeView.ContextMenu = treeView.Resources["CaseContextMenu"] as System.Windows.Controls.ContextMenu;
                    break;

                default:
                    treeView.ContextMenu = null;
                    break;
            }
        }

        /// <summary>
        /// Exports to CSV.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The e.</param>
        private void ExportToCsvClick(object sender, RoutedEventArgs e)
        {
            var treeView = TreeMain;
            var selectedItem = treeView.SelectedItem as TreeViewItem;

            if (selectedItem == null)
            {
                return;
            }

            var item = (TfsTestItem)selectedItem.Tag;

            switch (item.Type)
            {
                case TfsTestItemType.TestPlan:
                    var saveFileDialog = new SaveFileDialog
                    {
                        InitialDirectory = Path.GetPathRoot(Environment.SystemDirectory),
                        FileName = "Export_" + item.Type.ToString() + "_" + item.Name,
                        CheckPathExists = true,
                        CheckFileExists = false,
                        CreatePrompt = false,
                        OverwritePrompt = true,
                        AddExtension = true,
                        DefaultExt = Properties.Resources.SaveAsFileDialogDefaultExtension,
                        Filter = Properties.Resources.SaveAsFileDialogFilter,
                        FilterIndex = 1
                    };

                    if (saveFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    {
                        var fileName = saveFileDialog.FileName;
                        ExportTest(item, fileName);
                    }
                    break;

                case TfsTestItemType.TestSuite:
                case TfsTestItemType.TestCase:
                    const string caption = "TFS Test Export";
                    MessageBox.Show("Option not available in this version. You must export a full test plan.", caption, MessageBoxButton.OK, MessageBoxImage.Information);
                    break;
            }
        }

        #endregion

        #endregion

        #region Migration

        /// <summary>
        /// Handles the Click event of the exportMenuItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void MigrateClick(object sender, RoutedEventArgs e)
        {
            if (_sourceProject == null || _destinationProject == null)
            {
                return;
            }

            var prefix = string.Format("Migration_{0}_", DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss"));
            var logFile = prefix + "TestPlanMigration.log";
            var error = false;

            using (new WaitCursor())
            {
                using (var logger = new StreamWriter(logFile, false, Encoding.UTF8))
                {
                    try
                    {
                        var migrator = new TestProjectMigrator(_sourceProject, _destinationProject, logger);

                        logger.WriteLine("Will migrate with prefix : " + prefix);

                        // To avoid same project name, add a prefix to plan (else check _sourceProject.Project.Uri.AbsolutePath == _destinationProject.Project.Uri.AbsolutePath)
                        migrator.MigrateTestPlans(prefix);

                        logger.WriteLine("Done with prefix : " + prefix);
                    }
                    catch (Exception ex)
                    {
                        logger.WriteLine("Exception : " + ex.Message);

                        if (ex.InnerException != null)
                        {
                            logger.WriteLine("InnerException : " + ex.InnerException.Message);
                        }

                        error = true;
                    }
                }
            }

            const string caption = "TFS Test Plan Migration";
            var checkLogsMessage = Environment.NewLine + Environment.NewLine + "Check logs in : " + AppDomain.CurrentDomain.BaseDirectory + logFile;

            if (!error)
            {
                MessageBox.Show("Done." + checkLogsMessage, caption, MessageBoxButton.OK, MessageBoxImage.Information);
            }
            else
            {
                MessageBox.Show("Error(s) occured." + checkLogsMessage, caption, MessageBoxButton.OK, MessageBoxImage.Error);
            }

            ClearUI();
        }

        #endregion

        #region Export

        /// <summary>
        /// Exports the test.
        /// </summary>
        /// <param name="item">The item.</param>
        /// <param name="exportToFileName">Name of the export to file.</param>
        private void ExportTest(TfsTestItem item, string exportToFileName)
        {
            var logFile = exportToFileName.Replace(Properties.Resources.SaveAsFileDialogDefaultExtension, "log");
            var error = false;
            const string caption = "TFS Test Export";

            using (new WaitCursor())
            {
                using (var logger = new StreamWriter(logFile, false, Encoding.UTF8))
                {
                    try
                    {
                        var exporter = new TestProjectExporter(_sourceProject, item, exportToFileName, logger);

                        switch (item.Type)
                        {
                            case TfsTestItemType.TestPlan:
                                exporter.ExportTestPlan();
                                break;

                            case TfsTestItemType.TestSuite:
                            case TfsTestItemType.TestCase:
                                MessageBox.Show("Option not available in this version. You must export a full test plan.", caption, MessageBoxButton.OK, MessageBoxImage.Information);
                                break;
                        }
                    }
                    catch (Exception ex)
                    {
                        logger.WriteLine("Exception : " + ex.Message);

                        if (ex.InnerException != null)
                        {
                            logger.WriteLine("InnerException : " + ex.InnerException.Message);
                        }

                        error = true;
                    }
                }
            }

            var checkLogsMessage = Environment.NewLine + Environment.NewLine + "Check logs in : " + logFile;

            if (!error)
            {
                var checkMessage = Environment.NewLine + Environment.NewLine + "Check export result in : " + exportToFileName;
                MessageBox.Show("Done." + checkMessage + checkLogsMessage, caption, MessageBoxButton.OK, MessageBoxImage.Information);
            }
            else
            {
                MessageBox.Show("Error(s) occured." + checkLogsMessage, caption, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        #endregion
    }
}